import requests
import time
from enum import IntEnum

class ChargeType(IntEnum):
  kCount = 1
  kTime = 2


class Session:
  host:str
  sessionToken:str = None
  verifyKey:str = None
  errorCode:int = 0
  data:str = None
  notice:str = None
  balance:int = 0
  chargeType:ChargeType
  
  def __init__(self,secretId:str,secretKey:str,projectId:int,server_host:str = "https://api.keyikami.com/api/v1"):
    self.secretId = secretId
    self.secretKey = secretKey
    self.projectId = projectId
    self.host = server_host
  
  def login(self,username:str,machineId:str,password:str = None,time_shift:int=0):
    nowTime = int(time.time())+time_shift
    response = requests.post(f"{self.host}/login",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "projectId":self.projectId,
      "username":username,
      "machineId":machineId,
      "timestamp":nowTime,
      "password":password
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] != 0:
      self.errorCode = data["code"]
      return False
    print(data)
    self.sessionToken = data["sessionToken"]
    self.verifyKey = data["nextKey"]
    self.data = data["data"]
    self.notice = data["notice"]
    self.balance = data["balance"]
    self.chargeType = ChargeType(data["chargeType"])
    return True
  
  def tick(self):
    response = requests.post(f"{self.host}/tick",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
      "key":self.verifyKey
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    
    data = response.json()
    if data["code"] == 0:
      self.verifyKey = data["nextKey"]
      return True
    
    self.errorCode = data["code"]
    return False

  def logout(self):
    response = requests.post(f"{self.host}/logout",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
      "key":self.verifyKey
    })
    if response.status_code  != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      self.sessionToken = None
      self.verifyKey = None
      return True
    self.errorCode = data["code"]
    return False
  
  def setValue(self,**kwargs):
    response = requests.post(f"{self.host}/set_value",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
      "data":kwargs
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False
  
  def getValue(self,*args):
    response = requests.post(f"{self.host}/get_value",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
      "keys":args
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return None
    data = response.json()
    if data["code"] == 0:
      return data["values"]
    self.errorCode = data["code"]
    return None
  
  def call(self,method,*args):
    response = requests.post(f"{self.host}/call",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
      "method":method,
      "args":args
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return None
    data = response.json()
    if data["code"] == 0:
      return data["data"]
    self.errorCode = data["code"]
    return None
  
  def setConfig(self,config:str):
    response = requests.post(f"{self.host}/set_config",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
      "data":config
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False
  
  def getConfig(self):
    response = requests.post(f"{self.host}/get_config",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "sessionToken":self.sessionToken,
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return None
    data = response.json()
    if data["code"] == 0:
      return data["data"]
    self.errorCode = data["code"]
    return None
  
  def _send_code(self,email:str,type:int):
    response = requests.post(f"{self.host}/send_verify_code",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "email":email,
      "projectId":self.projectId,
      "type":type
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False

  def sendRegisterCode(self,email:str):
    return self._send_code(email,1)
  
  def sendResetPasswordCode(self,email:str):
    return self._send_code(email,2)
  
  def registerAccount(self,email:str,password:str,nickname:str,verifyCode:int):
    response = requests.post(f"{self.host}/register_account",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "projectId":self.projectId,
      "email":email,
      "password":password,
      "nickname":nickname,
      "verifyCode":verifyCode
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False
  
  def resetPassword(self,email:str,password:str,verifyCode:int):
    response = requests.post(f"{self.host}/reset_password",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "projectId":self.projectId,
      "email":email,
      "password":password,
      "verifyCode":verifyCode
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False
  
  def changePassword(self,email:str,password:str,newPassword:str):
    response = requests.post(f"{self.host}/change_password",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "projectId":self.projectId,
      "email":email,
      "password":password,
      "newPassword":newPassword
    })
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False
  
  def recharge(self,account:str,keyCode:str,forceReplace:bool = False):
    response = requests.post(f"{self.host}/recharge",json={
      "secretId":self.secretId,
      "secretKey":self.secretKey,
      "projectId":self.projectId,
      "account":account,
      "keyCode":keyCode,
      "forceReplace":forceReplace
    })
    if response.status_code != 200:
      self.errorCode = response.status_code
      return False
    data = response.json()
    if data["code"] == 0:
      return True
    self.errorCode = data["code"]
    return False

class ErrorCode(IntEnum):
  kSuccess = 0                       # 请求成功
  kTooManyRequests = 429             # 请求过多，频繁的请求会导致返回此结果，如果出现此结果，请降低请求频率，否则会被服务器加入黑名单
  kUnknownError = 1000               # 未知错误，通常不会出现这种情况
  kInvalidSecretIdOrKey = 1001       # 无效的secretId或secretKey，secretId或secretKey错误
  kInvalidAccountOrPassword = 1002             # 无效的Account或Password，Account或Password错误
  kAccountSuspended = 1003           # Account被禁用
  kInvalidProject = 1004            # 无效的软件ID，软件的ID错误，或者与Account绑定的软件ID不匹配
  kInvalidTimestamp = 1005           # 无效的时间戳，时间戳需要当前时间，如果时间戳与当前时间超过5秒，则视为无效
  kInvalidMachineId = 1006           # 无效的machineId，machineId的格式不正确
  kInvalidSessionTokenOrKey = 1007   # 无效的sessionToken或key
  kTooManyDevice = 1008              # 设备过多,当前登录的Account的可登录设备数量达到上限
  kSessionLimit = 1009               # session限制，账号同时在线的会话数量达到上限
  kAccountBalanceNotEnough = 1010,   # 账号余额不足
  # Cloud related error codes
  kInvalidCloudFunction = 1100       # 无效的云函数，云函数不存在
  kCallException = 1101              # 云函数调用异常

  # Account related error codes
  kAccountAlreadyExist = 1200       # 账号已存在
  kInvalidVerifyCode = 1201          # 无效的验证码
  kInvalidVerifyCodeType = 1202      # 无效的验证码类型
  kChargeTypeOrSessionLimitNotMatch = 1203 # 充值类型或登录设备限制不匹配
  kKeyCardNotExistOrUsed = 1204       # 卡密不存在或已使用